/*
 * Copyright (c) Jiandong.
 *
 * This source code is licensed under the MIT license found in the
 * LICENSE file in the root directory of this source tree.
 */


import util from '@ohos.util';
import buffer from '@ohos.buffer';
import fileio from '@ohos.fileio';
import ArrayList from '@ohos.util.ArrayList';
import HashSet from '@ohos.util.HashSet';
import hilog from '@ohos.hilog';
import resmgr from "@ohos.resourceManager";
import List from '@ohos.util.List';

import { TypescriptModuleWrapper } from './TypescriptModuleWrapper';
import { ReactCallback } from './ReactCallback';
import { NativeUIManagerMessage } from '../uimanager/NativeViewRenderManager';
import { DVModelContainer } from '../uimanager/DynamicView';
import { NativeViewRenderManager } from '../uimanager/NativeViewRenderManager';
import { NativeModule } from './NativeModule';
import { TurboModuleRegistry } from '../turbomodule/core/interface/TurboModuleRegistry'
import { RuntimeScheduler } from './RuntimeScheduler';
import { JSIModuleSpec } from './JSIModuleSpec';
import { RuntimeExecutor } from './RuntimeExecutor';
import { ReactQueueConfiguration } from './queue/ReactQueueConfiguration';
import { AssetManager } from './AssetManager';
import { NativeArrayInterface } from './NativeArrayInterface';
import { ReactQueueConfigurationImpl } from './queue/ReactQueueConfigurationImpl';
import { Assertions } from '../inner/Assertions';
import { ReactBridge } from './ReactBridge';
import { ReactFeatureFlags } from '../config/ReactFeatureFlags';
//import { TurboModuleRegistry } from '../core/interface/TurboModuleRegistry';
import { WritableNativeArray } from './WritableNativeArray';
import { NativeArray } from './NativeArray';
import { ModuleHolder } from './ModuleHolder';
import { JavaScriptContextHolder } from './JavaScriptContextHolder';
import { JavaScriptModuleRegistry } from './JavaScriptModuleRegistry';
import { NativeModuleRegistry } from './NativeModuleRegistry';
import { JSIModuleRegistry } from './JSIModuleRegistry';
import { HybridData } from '../../napi/HybridData';
import { JSIModule } from './JSIModule';
import { JSBundleLoader } from './JSBundleLoader';
import { JavaScriptExecutor } from './JavaScriptExecutor';
import { ReactQueueConfigurationSpec } from './queue/ReactQueueConfigurationSpec';
import { CatalystInstance } from './CatalystInstance';
import { MessageQueueThread, Runnable } from './queue/MessageQueueThread'
//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by FernFlower decompiler)
//

import * as Communication from '../common/Communication'

export class CatalystInstanceImpl implements CatalystInstance {
  private static readonly Tag = "React CatalystInstanceImpl"
  // -> private static readonly UIManagerModuleMessage = 1
  //    private static readonly sNextInstanceIdForTrace: number; // AtomicInteger
  private readonly mReactQueueConfiguration: ReactQueueConfigurationImpl;
  //    private readonly mBridgeIdleListeners: CopyOnWriteArrayList<NotThreadSafeBridgeIdleDebugListener>;
  // -> private mPendingJSCalls: number; //AtomicInteger
  //    private readonly string mJsPendingCallsTitleForTrace;
  private /*volatile*/  mDestroyed: boolean;
  //    private readonly TraceListener mTraceListener;
  // -> private readonly mJSModuleRegistry: JavaScriptModuleRegistry;
  private readonly mJSBundleLoader: JSBundleLoader;
  // -> private readonly mJSCallsPendingInit: ArrayList<PendingJSCall>;
  //    private readonly Object mJSCallsPendingInitLock;
  // -> private readonly mNativeModuleRegistry: NativeModuleRegistry;
  // -> private readonly mJSIModuleRegistry: JSIModuleRegistry;
  //    private readonly mJSExceptionHandler: JSExceptionHandler;
  private readonly mNativeModulesQueueThread: MessageQueueThread;
  private mNativeViewRenderManager: NativeViewRenderManager;
  private mInitialized: boolean;
  // -> private /*volatile*/ mAcceptCalls: boolean;
  private mJSBundleHasLoaded: boolean = false;
  private mSourceURL?: string;
  // -> private mJavaScriptContextHolder?: JavaScriptContextHolder;
  // -> private /*volatile*/ mTurboModuleRegistry: TurboModuleRegistry;
  // -> private mTurboModuleManagerJSIModule?: JSIModule;
  // -> private readonly mHybridData?: HybridData;


//  private readonly RunBundle: number = 0
//  private readonly RunApplication: number = 1
//  private readonly ProcessPackages: number = 2
//  private readonly OnHostForeground: number = 3

  //    private static /*native*/   initHybrid(var0: boolean, var1: boolean): HybridData {}

  //    public /*native*/ getJSCallInvokerHolder(): CallInvokerHolderImpl { return null }
  //
  //    public /*native*/ getNativeCallInvokerHolder(): CallInvokerHolderImpl { return null }

  public constructor(reactQueueConfigurationSpec: ReactQueueConfigurationSpec, jsExecutor: JavaScriptExecutor, jsBundleLoader: JSBundleLoader) {

//  public constructor(reactQueueConfigurationSpec: ReactQueueConfigurationSpec, jsExecutor: JavaScriptExecutor,
//                     nativeModuleRegistry: NativeModuleRegistry, jsBundleLoader: JSBundleLoader /*jSExceptionHandler: JSExceptionHandler*/
//  ) {
    // -> this.mPendingJSCalls = 0 // new AtomicInteger(0);
    //        this.mJsPendingCallsTitleForTrace = "pending_js_calls_instance" + sNextInstanceIdForTrace.getAndIncrement();
    this.mDestroyed = false;
    // -> this.mJSCallsPendingInit = new ArrayList();
    //        this.mJSCallsPendingInitLock = new Object();
    // -> this.mJSIModuleRegistry = new JSIModuleRegistry();
    this.mInitialized = false;
    // -> this.mAcceptCalls = false;
    // -> this.mTurboModuleRegistry = null;
    // -> this.mTurboModuleManagerJSIModule = null;
    hilog.info(0x0, CatalystInstanceImpl.Tag, '%{public}s', "constructor.");
    //        Systrace.beginSection(0L, "createCatalystInstanceImpl");
    //        if (ReactFeatureFlags.enableRuntimeSchedulerInTurboModule && !ReactFeatureFlags.enableRuntimeScheduler) {
    //            Assertions.assertUnreachable();
    //        }

    //        this.mHybridData = CatalystInstanceImpl.initHybrid(ReactFeatureFlags.enableRuntimeScheduler, ReactFeatureFlags.enableRuntimeSchedulerInTurboModule);
    this.mReactQueueConfiguration = ReactQueueConfigurationImpl.create(reactQueueConfigurationSpec);
    //        this.mBridgeIdleListeners = new CopyOnWriteArrayList();
    // -> this.mNativeModuleRegistry = nativeModuleRegistry;
    //this.mJSModuleRegistry = new JavaScriptModuleRegistry();
    this.mJSBundleLoader = jsBundleLoader;
    //        this.mJSExceptionHandler = jSExceptionHandler;
    this.mNativeModulesQueueThread = this.mReactQueueConfiguration.getNativeModulesQueueThread();
    //        this.mTraceListener = new CatalystInstanceImpl.JSProfilerTraceListener(this);
    //        Systrace.endSection(0L);
    hilog.info(0x0000, CatalystInstanceImpl.Tag, '%{public}s', 'Initializing React Xplat Bridge before initializeBridge');
    //        Systrace.beginSection(0L, "initializeCxxBridge");
    //        if (ReactFeatureFlags.warnOnLegacyNativeModuleSystemUse) {
    //            this.warnOnLegacyNativeModuleSystemUse();
    //        }


    //this.initializeBridge(new BridgeCallback(this), jsExecutor, this.mReactQueueConfiguration.getJSQueueThread(),
                         // this.mNativeModulesQueueThread, null, null ) //this.mNativeModuleRegistry.getJavaModules(this), this.mNativeModuleRegistry.getCxxModules());
    this.initializeBridge(jsExecutor, jsBundleLoader)
    hilog.info(0x0000, CatalystInstanceImpl.Tag, '%{public}s', "Initializing React Xplat Bridge after initializeBridge");
    //        Systrace.endSection(0L);
    //        this.mJavaScriptContextHolder = new JavaScriptContextHolder(this.getJavaScriptContext());

  }

  public getNativeModuleRegistry() {
    return null;
//    return this.mNativeModuleRegistry;
  }


  static staticCall() {
    ReactBridge.staticInit();
    //        sNextInstanceIdForTrace = new AtomicInteger(1);
  }

  //    public extendNativeModules(modules: NativeModuleRegistry) {
  ////        this.mNativeModuleRegistry.registerModules(modules);
  ////        HashSet<JavaModuleWrapper> javaModules = modules.getJavaModules(this);
  ////        HashSet<ModuleHolder> cxxModules = modules.getCxxModules();
  ////        this.jniExtendNativeModules(javaModules, cxxModules);
  //    }

  //    /*native*/ private  jniExtendNativeModules(var1: HashSet<JavaModuleWrapper> , var2: HashSet<ModuleHolder> ) {}

  public setSourceURLs(deviceURL: string, remoteURL: string) {
    this.mSourceURL = deviceURL;
    this.napiSetSourceURL(remoteURL);
  }

  /*native*/
  // -> private  initializeBridge(var1: ReactCallback, var2: JavaScriptExecutor, var3: MessageQueueThread, var4: MessageQueueThread,
  // ->                           var5: HashSet<TypescriptModuleWrapper> , var6: HashSet<ModuleHolder>) {
  private  initializeBridge(var1: JavaScriptExecutor, var2: JSBundleLoader) {
    this.mReactQueueConfiguration?.getJSQueueThread()?.getWorker()?.postMessage({ message: Communication.InitializeBridge, executor: var1, loader: var2 });
  }

  private initializeRuntime(): void {
    this.mReactQueueConfiguration?.getJSQueueThread()?.getWorker()?.postMessage({ message: Communication.InitializeRuntime });
  }

  public registerSegment(segmentId: number, path: string) {
    this.napiRegisterSegment(segmentId, path);
  }

  public loadScriptFromResource(resourceManager: resmgr.ResourceManager, resourceURL: string, loadSynchronously: boolean) {
    hilog.info(0x0000, CatalystInstanceImpl.Tag, `loadScriptFromResource ` + "resourceURL: "+ resourceURL)
    this.mSourceURL = resourceURL;

    try {
      resourceManager.getRawFileContent(resourceURL + '.abc', (error, value) => {
        if (error != null) {
          hilog.info(0x0000, CatalystInstanceImpl.Tag, "getRawFileContent error is " + error);
        } else {
          var textDecoder = new util.TextDecoder("utf-8",{ignoreBOM: true});
          var retStr = textDecoder.decode( value , {stream: false});
          hilog.info(0x0000, CatalystInstanceImpl.Tag, "getRawFileContent abcResource is " + retStr);
          //todo , should  support transfer abcResource
          Uint8Array
          this.mReactQueueConfiguration?.getJSQueueThread()?.getWorker()?.postMessage({ message: Communication.RunBundleFromBuffer, data: value.buffer as ArrayBuffer });
        }
      });
    } catch (error) {
      hilog.info(0x0000, CatalystInstanceImpl.Tag, `callback getRawFileContent failed, error code: ${error.code}, message: ${error.message}.`)
    }
      // this.napiLoadScriptFromAssets(assetManager, assetURL, loadSynchronously);
  }

  public loadScriptFromFile(fileName: string, sourceURL: string, loadSynchronously: boolean) {
    hilog.info(0x0000, CatalystInstanceImpl.Tag, " loadScriptFromFile: fileName222: "+ fileName + " sourceURL: " + sourceURL + " loadSynchronously: " +  loadSynchronously)
//    /data/app/el2/100/base/com.example.myapplicationstage/haps/entry/files/BridgeReactNativeDevBundle.js

//    fileName: /data/storage/el2/base/haps/entry/files/BridgeReactNativeDevBundle.js
//    sourceURL: http://localhost:8081/index.bundle?platform=android&dev=true&minify=false&app=com.example.myapplicationstage&modulesOnly=false&runModule=true&runtimeBytecodeVersion=100
//    loadSynchronously: false

    this.mSourceURL = sourceURL;
    this.mReactQueueConfiguration?.getJSQueueThread()?.getWorker()?.postMessage({ message: Communication.RunBundleFromFile, file: "../../el2/base/files/abc.js" })
//    this.mReactQueueConfiguration?.getJSQueueThread()?.getWorker()?.postMessage({ message: Communication.RunBundleFromFile, file: "/data/app/el2/100/base/com.example.myapplicationstage/haps/entry/files/abc.abc" })
//    return

//    if (true || loadSynchronously) {
//      try {
//        let data =  new ArrayBuffer(5 * 10204 * 1024)
//        let writeFd = fileio.openSync("/data/storage/el2/base/haps/entry/files/abc.abc", 0o2 | 0o100, 0o666)
//        let stream = fileio.fdopenStreamSync(writeFd, "r")
//        let readLength = stream.readSync(data, {
//          offset: 0,
//          length: data.byteLength,
//          position: 0
//        })
//
////        let value = buffer.from(data)
//        hilog.info(0x0000, CatalystInstanceImpl.Tag, `loadScriptFromFile success:` + "length: "+ readLength)
////        hilog.info(0x0000, CatalystInstanceImpl.Tag, " data: " + value.toString()) //
//        this.mReactQueueConfiguration?.getJSQueueThread()?.getWorker()?.postMessage({ message: Communication.RunBundleFromBuffer, buffer: data }); //transfer [data]
//      } catch (error) {
//        hilog.info(0x0000, CatalystInstanceImpl.Tag, `loadScriptFromFile failed, error code: ${error.code}, message: ${error.message}.`)
//      }
//    }
    // this.napiLoadScriptFromFile(fileName, sourceURL, loadSynchronously);
  }

  public loadSplitBundleFromFile(fileName: string, sourceURL: string) {
    this.mReactQueueConfiguration?.getJSQueueThread()?.getWorker()?.postMessage({ message: Communication.RunBundleFromFile, file: fileName, source: sourceURL, async: false });
    // this.napiLoadScriptFromFile(fileName, sourceURL, false);
  }

  public directRunScript() {
    hilog.info(0x0000, CatalystInstanceImpl.Tag, '%{public}s', "directRunScript: " + `${Communication.RunBundle}`);
    this.mReactQueueConfiguration?.getJSQueueThread()?.getWorker()?.postMessage({ message: Communication.DirectRunScript });
  }

  public processPackages(callBack: (type: string) => void): void {
    hilog.info(0x0000, CatalystInstanceImpl.Tag, '%{public}s', "processPackages");
    this.mReactQueueConfiguration?.getJSQueueThread()?.getWorker()?.postMessage({ message: Communication.ProcessPackages });
    this.mReactQueueConfiguration?.getJSQueueThread()?.getWorker()?.addEventListener("processPackagesFinished", (e) => {
        callBack("processPackagesFinished");
    })
     this.mNativeViewRenderManager = new NativeViewRenderManager()
  }

  public setUpUIListener(callBack: (type: string) => void) {
//    this.mReactQueueConfiguration?.getJSQueueThread()?.getWorker()?.addEventListener("processPackages", (e) => {
//      callBack("processPackages");
//    })
  }

  public runJSBundle(callBack: (type: string) => void) {
    hilog.info(0x0000, CatalystInstanceImpl.Tag, '%{public}s', "runJSBundle");
    Assertions.assertCondition(!this.mJSBundleHasLoaded, "JS bundle was already loaded!");

    this.mJSBundleLoader.loadScript(this);

    let worker = this.mReactQueueConfiguration?.getJSQueueThread()?.getWorker()
//    if (!worker) {
//      throw Error("runApplication error due worker is null or undefined")
//    }
//    worker.postMessage({ message: Communication.RunBundle});
    worker.addEventListener("runJSBundleFinished", (e) => {
      if (!callBack) callBack("runJSBundleFinished");
      this.mJSBundleHasLoaded = true;
    })

//    this.mAcceptCalls = true;
//
//    let iter = this.mJSCallsPendingInit[Symbol.iterator]();
//    let temp = iter.next().value;
//    while (temp != undefined) {
//      let jsfunction = temp as PendingJSCall;
//      jsfunction.call(this);
//      temp = iter.next().value;
//    }
//    this.mJSCallsPendingInit.clear()
   // this.mJSBundleHasLoaded = true;

    //        Systrace.registerListener(this.mTraceListener);
  }

  public attachReactRoot(moduleContainer: DVModelContainer) {
    hilog.info(0x0000, CatalystInstanceImpl.Tag, '%{public}s', "attachReactRoot");
    if (!moduleContainer || !this.mNativeViewRenderManager) {
      hilog.info(0x0000, CatalystInstanceImpl.Tag, '%{public}s', "moduleContainer or mNativeViewRenderManager is null");
      return;
    }
    this.mNativeViewRenderManager.attachReactRoot(moduleContainer)
  }

  public runApplication(callBack: (type: string) => void) {
    hilog.info(0x0000, CatalystInstanceImpl.Tag, '%{public}s', "runApplication");
    //        Assertions.assertCondition(!this.mJSModuleRegistry, "JS bundle was already loaded!");
    //TODO : should call appregisry to get mJSModuleRegistry to
    let worker = this.mReactQueueConfiguration?.getJSQueueThread()?.getWorker()
    if (!worker) {
      throw Error("runApplication error due worker is null or undefined")
    }
    worker.postMessage({ message: Communication.RunApplication });
    worker.addEventListener("runApplicationFinished", (e) => {
      if (callBack) callBack("runApplicationFinished");
    })
  }

  public onHostForeground() {
    hilog.info(0x0000, CatalystInstanceImpl.Tag, '%{public}s', "onHostForeground");
    //        Assertions.assertCondition(!this.mJSModuleRegistry, "JS bundle was already loaded!");
    //TODO : should call appregisry to get mJSModuleRegistry to

  }

  public hasRunJSBundle(): boolean {
    //        synchronized(this.mJSCallsPendingInitLock) {
    // -> return this.mJSBundleHasLoaded && this.mAcceptCalls;
    //        }
    return this.mJSBundleHasLoaded;
  }

  //    @Nullable
  public getSourceURL(): string {
    return this.mSourceURL;
  }

  // TODO Frmk bridge work
  public callFunction(module: string, method: string, args: NativeArray) {
    // -> this.callFunctionImpl(new PendingJSCall(module, method, args));
  }

// ->  public callFunctionImpl(fun: PendingJSCall) {

//   if (this.mDestroyed) {
//      let call = fun.toString();
//      hilog.warn(0x0000, CatalystInstanceImpl.Tag, '%{public}s', "Calling JS function after bridge has been destroyed: " + call);
//    } else {
//      if (!this.mAcceptCalls) {
//        this.mJSCallsPendingInit.add(fun);
//        return;
//      }
//      fun.call(this);
//    }
//  }

  public invokeCallback(callbackID: number, args: NativeArrayInterface) {
//   ->  if (this.mDestroyed) {
//      hilog.warn(0x0000, CatalystInstanceImpl.Tag, '%{public}s', "Invoking JS callback after bridge has been destroyed.");
//    } else {
//      this.napiCallJSCallback(callbackID, args as NativeArray);
//    }
  }

  //    @ThreadConfined("UI")
  public destroy() {
    //        FLog.d("ReactNative", "CatalystInstanceImpl.destroy() start");
    //        UiThreadUtil.assertOnUiThread();
    if (!this.mDestroyed) {
      //            ReactMarker.logMarker(ReactMarkerConstants.DESTROY_CATALYST_INSTANCE_START);
      this.mDestroyed = true;
      //            this.mNativeModulesQueueThread.runOnQueue(new Runnable() {
      //                public void run() {
      //                    CatalystInstanceImpl.this.mNativeModuleRegistry.notifyJSInstanceDestroy();
      //                    CatalystInstanceImpl.this.mJSIModuleRegistry.notifyJSInstanceDestroy();
      //                    boolean wasIdle = CatalystInstanceImpl.this.mPendingJSCalls.getAndSet(0) == 0;
      //                    NotThreadSafeBridgeIdleDebugListener listener;
      //                    if (!CatalystInstanceImpl.this.mBridgeIdleListeners.isEmpty()) {
      //                        for(Iterator var2 = CatalystInstanceImpl.this.mBridgeIdleListeners.iterator(); var2.hasNext(); listener.onBridgeDestroyed()) {
      //                            listener = (NotThreadSafeBridgeIdleDebugListener)var2.next();
      //                            if (!wasIdle) {
      //                                listener.onTransitionToBridgeIdle();
      //                            }
      //                        }
      //                    }
      //
      //                    CatalystInstanceImpl.this.getReactQueueConfiguration().getJSQueueThread().runOnQueue(new Runnable() {
      //                        public void run() {
      //                            if (CatalystInstanceImpl.this.mTurboModuleManagerJSIModule != null) {
      //                                CatalystInstanceImpl.this.mTurboModuleManagerJSIModule.onCatalystInstanceDestroy();
      //                            }
      //
      //                            CatalystInstanceImpl.this.getReactQueueConfiguration().getUIQueueThread().runOnQueue(new Runnable() {
      //                                public void run() {
      //                                    AsyncTask.execute(new Runnable() {
      //                                        public void run() {
      //                                            CatalystInstanceImpl.this.mJavaScriptContextHolder.clear();
      //                                            CatalystInstanceImpl.this.mHybridData.resetNative();
      //                                            CatalystInstanceImpl.this.getReactQueueConfiguration().destroy();
      //                                            FLog.d("ReactNative", "CatalystInstanceImpl.destroy() end");
      //                                            ReactMarker.logMarker(ReactMarkerConstants.DESTROY_CATALYST_INSTANCE_END);
      //                                        }
      //                                    });
      //                                }
      //                            });
      //                        }
      //                    });
      //                }
      //            });
      //            Systrace.unregisterListener(this.mTraceListener);
    }
  }

  public isDestroyed(): boolean {
    return this.mDestroyed;
  }

  //    @VisibleForTesting
  public initialize() {
    hilog.debug(0x0000, CatalystInstanceImpl.Tag, '%{public}s', "CatalystInstanceImpl.initialize()");
    Assertions.assertCondition(!this.mInitialized, "This catalyst instance has already been initialized");
    //Assertions.assertCondition(this.mAcceptCalls, "RunJSBundle hasn't completed.");
//    this.mInitialized = true;
//
    this.mReactQueueConfiguration?.getJSQueueThread()?.getWorker()?.postMessage({ message: Communication.CreateAndSetUpContext });
    this.mReactQueueConfiguration?.getJSQueueThread()?.getWorker()?.addEventListener(Communication.CreateAndSetUpContextFinished, (e) => {
      this.mInitialized = true;
      //callBack("processPackagesFinished");
    })


    //        this.mNativeModulesQueueThread.runOnQueue(new Runnable(this) {
    //            public void run() {
    //                catalystInstanceImpl.mNativeModuleRegistry.notifyJSInstanceInitialized();
    //            }
    //        });
  }

  public setUpMessageResponse(): void {
    hilog.info(0x0000, CatalystInstanceImpl.Tag, "setUpMessageResponse");
    this.mReactQueueConfiguration.getJSQueueThread().getWorker().onmessage = function(e) {
      hilog.info(0x0000, CatalystInstanceImpl.Tag, "onmessage 111");
      switch (e.data.message) {
        case Communication.UIManagerModuleMessage:
          hilog.info(0x0000, CatalystInstanceImpl.Tag, "UIManagerModuleMessage 111");
          this.mNativeViewRenderManager?.processMessage(e.data.data as NativeUIManagerMessage);
          break;
        default:
          hilog.info(0x0000, CatalystInstanceImpl.Tag, 'there is no module to Process to message: %{public}d', e.data.message as number);
          break;
      }
    }.bind(this)
  }

  public getReactQueueConfiguration(): ReactQueueConfiguration {
    return this.mReactQueueConfiguration;
  }

  //
  public getNativeModules(): HashSet<NativeModule> {
    throw Error("getNativeModules should not be called in ui thread")
    // -> let nativeModules: HashSet<NativeModule> = new HashSet();
    //        nativeModules.addAll(this.mNativeModuleRegistry.getAllModules());
    //        if (this.getTurboModuleRegistry() != null) {
    //            Iterator var2 = this.getTurboModuleRegistry().getModules().iterator();
    //
    //            while(var2.hasNext()) {
    //                TurboModule turboModule = (TurboModule)var2.next();
    //                nativeModules.add((NativeModule)turboModule);
    //            }
    //        }
    //
    // ->  return nativeModules;
  }

  public getJavaScriptContextHolder(): JavaScriptContextHolder {
    throw Error("getJavaScriptContextHolder should not be called in ui thread")
//    return this.mJavaScriptContextHolder;
  }

  public /*native */ getRuntimeExecutor(): RuntimeExecutor {
    throw Error("getRuntimeExecutor should not be called in ui thread")
  };

  public /*native */  getRuntimeScheduler(): RuntimeScheduler {
    throw Error("getRuntimeScheduler should not be called in ui thread")
  };

  /*native*/
  private warnOnLegacyNativeModuleSystemUse() {
  }

  /*native*/
  private napiSetSourceURL(var1: string) {
    hilog.info(0x0000, CatalystInstanceImpl.Tag, '%{public}s', "napiSetSourceURL");
  }

  /*native*/
  private napiRegisterSegment(var1: number, var2: string) {
    hilog.info(0x0000, CatalystInstanceImpl.Tag, '%{public}s', "napiRegisterSegment");
  }

  //    public getJSModule<T extends JavaScriptModule> (jsInterface: Class<T>): T {
  //        return this.mJSModuleRegistry.getJavaScriptModule(this, jsInterface);
  //    }
  //
  //    public hasNativeModule<T extends NativeModule> (Class<T> nativeModuleInterface): boolean {
  //        const moduleName: string  = this.getNameFromAnnotation(nativeModuleInterface);
  //        return this.getTurboModuleRegistry() != null && this.getTurboModuleRegistry().hasModule(moduleName) ? true : this.mNativeModuleRegistry.hasModule(moduleName);
  //    }
  //
  //    public  T getNativeModule<T extends NativeModule>(nativeModuleInterface: Class<T>): T {
  //        return this.getNativeModule(this.getNameFromAnnotation(nativeModuleInterface));
  //    }

  /*native*/
  private napiLoadScriptFromAssets(var1: AssetManager, var2: string, var3: boolean) {
    hilog.info(0x0000, CatalystInstanceImpl.Tag, '%{public}s', "napiLoadScriptFromAssets");
  }

  //    @Nullable
  //    public NativeModule getNativeModule(string moduleName) {
  //        if (this.getTurboModuleRegistry() != null) {
  //            TurboModule turboModule = this.getTurboModuleRegistry().getModule(moduleName);
  //            if (turboModule != null) {
  //                return (NativeModule)turboModule;
  //            }
  //        }
  //
  //        return this.mNativeModuleRegistry.hasModule(moduleName) ? this.mNativeModuleRegistry.getModule(moduleName) : null;
  //    }
  //
  //    private <T extends NativeModule> string getNameFromAnnotation(Class<T> nativeModuleInterface) {
  //        ReactModule annotation = (ReactModule)nativeModuleInterface.getAnnotation(ReactModule.class);
  //        if (annotation == null) {
  //            throw new IllegalArgumentException("Could not find @ReactModule annotation in " + nativeModuleInterface.getCanonicalName());
  //        } else {
  //            return annotation.name();
  //        }
  //    }

  /*native*/
  private napiLoadScriptFromFile(var1: string, var2: string, var3: boolean) {
    //todo , implement load related functonaliy
    hilog.info(0x0000, CatalystInstanceImpl.Tag, '%{public}s', "napiLoadScriptFromFile");




  }
  //
  //    private native void napiHandleMemoryPressure(int var1);
  //
  //    public void handleMemoryPressure(int level) {
  //        if (!this.mDestroyed) {
  //            this.napiHandleMemoryPressure(level);
  //        }
  //    }
  //
  //    public void addBridgeIdleDebugListener(NotThreadSafeBridgeIdleDebugListener listener) {
  //        this.mBridgeIdleListeners.add(listener);
  //    }
  //
  //    public void removeBridgeIdleDebugListener(NotThreadSafeBridgeIdleDebugListener listener) {
  //        this.mBridgeIdleListeners.remove(listener);
  //    }
  //
  //    public native void setGlobalVariable(string var1, string var2);

  /*native*/

  public callJSFunction(): void {
    throw Error("callJSFunction should not be called in ui thread")
  }

//->  public napiCallJSFunction(var1: string, var2: string, var3: NativeArray) {
//    throw Error("napiCallJSFunction should not be called in ui thread")
//  }

  /*native*/
//->  public napiCallJSCallback(var1: number, var2: NativeArray) {
//    throw Error("napiCallJSCallback should not be called in ui thread")
//  }

//->  private getTurboModuleRegistry(): TurboModuleRegistry {
//    throw Error("getTurboModuleRegistry should not be called in ui thread")
//    //        return ReactFeatureFlags.useTurboModules ? (TurboModuleRegistry)Assertions.assertNotNull(this.mTurboModuleRegistry, "TurboModules are enabled, but mTurboModuleRegistry hasn't been set.") : null;
//    // -> return this.mTurboModuleRegistry;
//  }

  //    public addJSIModules(jsiModules: List<JSIModuleSpec> ) {
  //        this.mJSIModuleRegistry.registerModules(jsiModules);
  //    }
  //
  //    public getJSIModule(moduleType: JSIModuleType): JSIModule {
  //        return this.mJSIModuleRegistry.getModule(moduleType);
  //    }

  /*native */
  private getJavaScriptContext(): null {
    throw Error("getJavaScriptContext should not be called in ui thread")
  }

//->   public incrementPendingJSCalls() {
//    this.mPendingJSCalls++
//    //        let oldPendingCalls:number = this.++mPendingJSCalls //.getAndIncrement();
//    //let  wasIdle = oldPendingCalls == 0;
//    //        Systrace.traceCounter(0L, this.mJsPendingCallsTitleForTrace, oldPendingCalls + 1);
//    //        if (wasIdle && !this.mBridgeIdleListeners.isEmpty()) {
//    //            this.mNativeModulesQueueThread.runOnQueue(new Runnable(this) {
//    //                public void run() {
//    //                    Iterator var1 = nCatalystInstanceImpl.mBridgeIdleListeners.iterator();
//    //
//    //                    while(var1.hasNext()) {
//    //                        NotThreadSafeBridgeIdleDebugListener listener = (NotThreadSafeBridgeIdleDebugListener)var1.next();
//    //                        listener.onTransitionToBridgeBusy();
//    //                    }
//    //
//    //                }
//    //            });
//    //        }
//
//  }

  //    public setTurboModuleManager(module: JSIModule) {
  //        this.mTurboModuleRegistry = module;
  //        this.mTurboModuleManagerJSIModule = module;
  //    }

//->  public decrementPendingJSCalls() {
//    this.mPendingJSCalls--
//    //        let newPendingCalls: number = this.mPendingJSCalls; //this.--mPendingJSCalls.decrementAndGet();
//    //        boolean isNowIdle = newPendingCalls == 0;
//    //        Systrace.traceCounter(0L, this.mJsPendingCallsTitleForTrace, newPendingCalls);
//    //        if (isNowIdle && !this.mBridgeIdleListeners.isEmpty()) {
//    //            this.mNativeModulesQueueThread.runOnQueue(new Runnable() {
//    //                public void run() {
//    //                    Iterator var1 = CatalystInstanceImpl.this.mBridgeIdleListeners.iterator();
//    //
//    //                    while(var1.hasNext()) {
//    //                        NotThreadSafeBridgeIdleDebugListener listener = (NotThreadSafeBridgeIdleDebugListener)var1.next();
//    //                        listener.onTransitionToBridgeIdle();
//    //                    }
//    //
//    //                }
//    //            });
//    //        }
//  }

  //    private onNativeException(e) {
  //        this.mJSExceptionHandler.handleException(e);
  //        this.mReactQueueConfiguration.getUIQueueThread().runOnQueue(new Runnable() {
  //            public void run() {
  //                CatalystInstanceImpl.this.destroy();
  //            }
  //        });
  //    }


}

export class CatalystInstanceImplBuilder {
  private mReactQueueConfigurationSpec?: ReactQueueConfigurationSpec;
  private mJSBundleLoader: JSBundleLoader;
//  private mRegistry: NativeModuleRegistry;
  private mJSExecutor: JavaScriptExecutor;

  //        private mJSExceptionHandler: JSExceptionHandler;

  public constructor() {
  }

  public setReactQueueConfigurationSpec(ReactQueueConfigurationSpec: ReactQueueConfigurationSpec): CatalystInstanceImplBuilder {
    this.mReactQueueConfigurationSpec = ReactQueueConfigurationSpec;
    return this;
  }

//  public setRegistry(registry: NativeModuleRegistry): CatalystInstanceImplBuilder {
//    this.mRegistry = registry;
//    return this;
//  }

  public setJSBundleLoader(jsBundleLoader: JSBundleLoader): CatalystInstanceImplBuilder {
    this.mJSBundleLoader = jsBundleLoader;
    return this;
  }

  public setJSExecutor(jsExecutor: JavaScriptExecutor): CatalystInstanceImplBuilder {
    this.mJSExecutor = jsExecutor;
    return this;
  }

  //        public setJSExceptionHandler(handler: JSExceptionHandler) {
  //            this.mJSExceptionHandler = handler;
  //            return this;
  //        }

  public build(): CatalystInstanceImpl {
    return new CatalystInstanceImpl(this.mReactQueueConfigurationSpec, this.mJSExecutor, this.mJSBundleLoader);
    //            return new CatalystInstanceImpl((ReactQueueConfigurationSpec)Assertions.assertNotNull(this.mReactQueueConfigurationSpec),
    //            (JavaScriptExecutor)Assertions.assertNotNull(this.mJSExecutor),
    //            (NativeModuleRegistry)Assertions.assertNotNull(this.mRegistry),
    //            (JSBundleLoader)Assertions.assertNotNull(this.mJSBundleLoader),
    //            (JSExceptionHandler)Assertions.assertNotNull(this.mJSExceptionHandler));
  }
}

//    private static class JSProfilerTraceListener implements TraceListener {
//        private final WeakReference<CatalystInstanceImpl> mOuter;
//
//        public JSProfilerTraceListener(CatalystInstanceImpl outer) {
//            this.mOuter = new WeakReference(outer);
//        }
//
//        public void onTraceStarted() {
//            CatalystInstanceImpl impl = (CatalystInstanceImpl)this.mOuter.get();
//            if (impl != null) {
//                ((com.facebook.react.bridge.Systrace)impl.getJSModule(com.facebook.react.bridge.Systrace.class)).setEnabled(true);
//            }
//
//        }
//
//        public void onTraceStopped() {
//            CatalystInstanceImpl impl = (CatalystInstanceImpl)this.mOuter.get();
//            if (impl != null) {
//                ((com.facebook.react.bridge.Systrace)impl.getJSModule(com.facebook.react.bridge.Systrace.class)).setEnabled(false);
//            }
//
//        }
//    }
//
//    private class NativeExceptionHandler implements QueueThreadExceptionHandler {
//        private NativeExceptionHandler() {
//        }
//
//        public void handleException(Exception e) {
//            CatalystInstanceImpl.this.onNativeException(e);
//        }
//    }
//

//    }
//
//class BridgeCallback implements ReactCallback {
////    private readonly mOuter: WeakRef;
//    private readonly mOuter: CatalystInstanceImpl;
//    constructor(outer: CatalystInstanceImpl) {
////         this.mOuter = new WeakRef(outer);
//      this.mOuter = outer;
//    }
//
//    public onBatchComplete() {
////        let impl = this.mOuter.deref() as CatalystInstanceImpl;
//        if (this.mOuter != null) {
//          this.mOuter.getNativeModuleRegistry().onBatchComplete();
//        }
//
//    }
//
//    public incrementPendingJSCalls() {
////        let impl = this.mOuter.deref() as CatalystInstanceImpl;
//        if (this.mOuter != null) {
//          this.mOuter.incrementPendingJSCalls();
//        }
//
//    }
//
//    public decrementPendingJSCalls() {
////        let impl = this.mOuter.deref() as CatalystInstanceImpl
//        if (this.mOuter != null) {
//          this.mOuter.decrementPendingJSCalls();
//        }
//
//    }
//}
//
//class PendingJSCall {
//  //    public mModule: string;
//  //    public mModule: string;
//  ////        @Nullable
//  //    public mArguments?: NativeArray;
//
//  public constructor(public mModule: string, public mMethod: string, public mArguments: NativeArray, public mDirectCall: boolean = true) {
//    //        this.mModule = module;
//    //        this.mMethod = method;
//    //        this.mArguments = arguments;
//  }
//
//  public call(catalystInstance: CatalystInstanceImpl) {
//    let args: NativeArray = this.mArguments != null ? this.mArguments : new WritableNativeArray() as NativeArray;
//    if (this.mDirectCall) {
//      catalystInstance.callJSFunction()
//    } else {
//      catalystInstance.napiCallJSFunction(this.mModule, this.mMethod, args);
//    }
//  }
//
//  public toString(): string {
//    return this.mModule + "." + this.mMethod + "(" + (this.mArguments == null ? "" : this.mArguments.toString()) + ")";
//  }
//}
